package com.ruoyi.procured.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.ruoyi.common.api.localInventory.LocalInventoryApi;
import com.ruoyi.common.api.localInventory.dto.LocalInventoryDto;
import com.ruoyi.common.api.procuredOrders.ProcuredOrdersStatusAPi;
import com.ruoyi.common.api.procuredStorage.ProcuredStorageApi;
import com.ruoyi.common.api.procuredStorage.dto.ProcuredStorageDto;
import com.ruoyi.common.api.sale.plan.SalePlanApi;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.ProcuredOrders;
import com.ruoyi.common.core.domain.entity.SysMenu;
import com.ruoyi.common.core.domain.entity.SysRole;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.uuid.IdUtils;
import com.ruoyi.procured.domain.Payment;
import com.ruoyi.procured.domain.PaymentRequest;
import com.ruoyi.procured.domain.PaymentReturn;
import com.ruoyi.procured.domain.vo.OrdersProductDTO;
import com.ruoyi.procured.domain.vo.ProcuredOrderAmountDTO;
import com.ruoyi.procured.mapper.*;
import com.ruoyi.procured.service.IPaymentRequestProcessService;
import com.ruoyi.procured.service.IPaymentRequestService;
import com.ruoyi.procured.service.IPaymentReturnService;
import com.ruoyi.sale.domain.ShipmentsProduct;
import com.ruoyi.sale.service.ShipmentsProductService;
import com.ruoyi.system.domain.SysUserRole;
import com.ruoyi.system.mapper.SysMenuMapper;
import com.ruoyi.system.mapper.SysRoleMapper;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.template.domain.TemplateDetail;
import com.ruoyi.template.mapper.TemplateMapper;
import com.ruoyi.template.service.TemplateDetailService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.NumberUtils;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 申请付款Service业务层处理
 * 
 * @author 刘广帆
 * @date 2024-10-01
 */
@Service
public class PaymentRequestServiceImpl implements IPaymentRequestService, ProcuredOrdersStatusAPi
{
    @Autowired
    private PaymentRequestMapper paymentRequestMapper;
    @Autowired
    private IPaymentRequestProcessService paymentRequestProcessService;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    @Autowired
    private SysRoleMapper sysRoleMapper;
    @Autowired
    private PaymentRequestProcessMapper paymentRequestProcessMapper;
    @Autowired
    private SysMenuMapper sysMenuMapper;
    @Autowired
    private TemplateMapper templateMapper;
    @Autowired
    private TemplateDetailService templateDetailService;
    @Autowired
    private PaymentMapper paymentMapper;
    @Autowired
    private ProcuredOrdersMapper procuredOrdersMapper;
    @Autowired
    private IPaymentReturnService paymentReturnService;
    @Autowired
    private ProcuredStorageApi procuredStorageApi;
    @Autowired
    private LocalInventoryApi localInventoryApi;
    @Autowired
    private SalePlanApi salePlanApi;
    @Autowired
    private ShipmentsProductService shipmentsProductService;
    /**
     * 最大可申请多少钱
     * @param ordersId
     * @return
     */
    @Override
    public ProcuredOrderAmountDTO selectProcuredOrderAmountDueById(String ordersId) {
        return paymentRequestMapper.selectProcuredOrderAmountDueById(ordersId);
    }

    /**
     * 新增申请付款
     * @param paymentRequest 申请应付款
     * @return 结果
     */
    @Override
    @Transactional
    public int insertPaymentRequestQuash(PaymentRequest paymentRequest, String procuredOrderId, Long userId, String componentPath) {

        //获取菜单ID
        List<TemplateDetail> templateDetails = CheckTemplateDetail(userId, componentPath);

        //查询该采购订单是否有已有申请单
        LambdaQueryWrapper<Payment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Payment::getProcuredOrderId,procuredOrderId);
        Payment payment = paymentMapper.selectOne(queryWrapper);
        if(null == payment){
            ProcuredOrders po = procuredOrdersMapper.selectProcuredOrdersByOrdersId(Long.valueOf(procuredOrderId));
            if(null == po){
                throw new ServiceException("获取采购单失败。");
            }
            payment = new Payment(IdUtils.fastSimpleUUID(),procuredOrderId,String.valueOf(po.getPlanId()));
            paymentMapper.insert(payment);
        }

        TemplateDetail firstDetail = templateDetails.get(0);
        Long reviewerUserId = Long.valueOf(firstDetail.getReviewerId());

        AtomicInteger index = new AtomicInteger(0);
        String paymentRequestCode = generateRequestCode(index.getAndIncrement());

        //插入申请单明细
        PaymentRequest pr = new PaymentRequest(IdUtils.fastSimpleUUID(),paymentRequestCode,
                Constants.PAYMENT_REVIEW_STATUS_PENDING,payment.getPaymentId(),
                procuredOrderId,Constants.PAYMENT_STATUS_ZERO,
                paymentRequest.getPaymentType(),paymentRequest.getPrepaymentCycle(),
                paymentRequest.getPrepaymentAmount(),paymentRequest.getPrepaymentRemark(),
                paymentRequest.getOtherFeeType(),paymentRequest.getOtherFeeAmount(),
                paymentRequest.getOtherFeeRemark(),paymentRequest.getApplicant(),userId,
                DateUtils.getNowDate(),Constants.CANCEL_STATUS_ZERO,
                paymentRequest.getPayableAmount(),reviewerUserId);
        int rows = paymentRequestMapper.insert(pr);

        //审核表插入审核流程记录
        paymentRequestProcessService.insertPaymentRequestProcessQuash(pr.getPaymentRequestId(), templateDetails, userId);

        //采购订单付款状态（0未申请付款，1部分申请付款，2已全部申请付款，3部分付款，4已全部付款）
        getProcuredOrderPaymentStatus(Long.valueOf(procuredOrderId));

        return rows;
    }
    /**
     * 申请退款
     * @param paymentRequest
     * @return
     */
    @Override
    @Transactional
    public int insertPaymentReturnQuash(PaymentRequest paymentRequest, String procuredOrderId, Long userId, String componentPath) {
        if(paymentRequest.getPaymentType().equals("2") || paymentRequest.getPaymentType().equals("3")){
            // 校验申请退款的产品中是否包含未提前结束的产品
            List<ShipmentsProduct> terminatedQuantity = shipmentsProductService.getSalesPlanDetailsByPurchaseOrderId(procuredOrderId);
            // 按 productId 去重，只保留遇到的第一个 ShipmentsProduct
            Map<Long, ShipmentsProduct> productMap = terminatedQuantity.stream()
                    .collect(Collectors.toMap(
                            ShipmentsProduct::getProductId,     // key：productId
                            Function.identity(),                // value：当前 ShipmentsProduct 对象
                            (existing, replacement) -> existing // 冲突时保留已有的那个
                    ));
            paymentRequest.getItems().forEach(
                    item -> {
                        ShipmentsProduct shipmentsProduct = productMap.get(Long.valueOf(item.getProductId()));
                        if(shipmentsProduct != null){
                            Integer infoCount = shipmentsProduct.getTerminatedQuantity();
                            if(infoCount == null){
                                throw new ServiceException("本次申请的产品中存在未提前结束的产品，请先提前结束之后再申请!");
                            }
                        } else {
                            throw new ServiceException("本次申请的产品中有部分产品在销售计划明细中不存在!");
                        }
                    }
            );
        }
//        if(true) throw new ServiceException("");
        //获取菜单ID
        List<TemplateDetail> templateDetails = CheckTemplateDetail(userId, componentPath);

        //查询该采购订单是否有已有申请单
        LambdaQueryWrapper<Payment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Payment::getProcuredOrderId,procuredOrderId);
        Payment payment = paymentMapper.selectOne(queryWrapper);
        if(null == payment){
            ProcuredOrders po = procuredOrdersMapper.selectProcuredOrdersByOrdersId(Long.valueOf(procuredOrderId));
            if(null == po){
                throw new ServiceException("获取采购单失败。");
            }
            payment = new Payment(IdUtils.fastSimpleUUID(),procuredOrderId,String.valueOf(po.getPlanId()));
            paymentMapper.insert(payment);
        }

        TemplateDetail firstDetail = templateDetails.get(0);
        Long reviewerUserId = Long.valueOf(firstDetail.getReviewerId());

        AtomicInteger index = new AtomicInteger(0);
        String paymentRequestCode = generateRequestCode(index.getAndIncrement());

        //插入申请单明细
        PaymentRequest pr = new PaymentRequest();
        pr.setPaymentRequestId(IdUtils.fastSimpleUUID());
        pr.setPaymentRequestCode(paymentRequestCode);
        pr.setPaymentReviewStatus(Constants.PAYMENT_REVIEW_STATUS_PENDING);
        pr.setPaymentId(payment.getPaymentId());
        pr.setProcuredOrderId(procuredOrderId);
        pr.setApplicant(paymentRequest.getApplicant());
        pr.setApplicantId(userId);
        pr.setApplicationTime(DateUtils.getNowDate());
        pr.setReviewerUserId(reviewerUserId);
        pr.setPaymentType(paymentRequest.getPaymentType());
        // 根据 paymentType 设置 paymentStatus
        if (paymentRequest.getPaymentType().equals("2")) {
            pr.setPaymentStatus(Constants.PAYMENT_STATUS_FOUR);
        } else if (paymentRequest.getPaymentType().equals("3")) {
            pr.setPaymentStatus(Constants.PAYMENT_STATUS_FIVE);
        } else if (paymentRequest.getPaymentType().equals("4")) {
            pr.setPaymentStatus(Constants.PAYMENT_STATUS_SIX);
        }
        pr.setReturnAmount(paymentRequest.getReturnAmount());
        pr.setReturnRemark(paymentRequest.getReturnRemark());
        int rows = paymentRequestMapper.insert(pr);

        List<OrdersProductDTO> productList =
                procuredOrdersMapper.selectOrdersProductListByOrdersId(Long.valueOf(procuredOrderId));
        // 转成 Map<sku, availableQty>
        Map<String, Integer> availMap = productList.stream()
                .collect(Collectors.toMap(
                        OrdersProductDTO::getSku,
                        item -> paymentRequest.getPaymentType().equals("2") ? item.getPurchaseQty() : item.getAvailableQty()
                ));

        List<PaymentReturn> items = paymentRequest.getItems();
        items.forEach(item -> {
            String sku = item.getSku();
            Integer available = availMap.get(sku);
            if (item.getQuantity() > available) {
                throw new ServiceException(
                        String.format("SKU “%s” 可退货数仅有 %d，您申请退货 %d，超出范围",
                                sku, available, item.getQuantity())
                );
            }
            item.setId(IdWorker.getId());
            item.setPaymentRequestId(pr.getPaymentRequestId());
            item.setAmount(item.getAmount());
            item.setFreight(item.getFreight());
            item.setProcuredOderId(procuredOrderId);
            item.setCreatedBy(paymentRequest.getApplicant());
            item.setCreateTime(DateUtils.getNowDate());
        });

        String paymentType = paymentRequest.getPaymentType();

        if(paymentType.equals("3") || paymentType.equals("4")){
            //商品库存锁定
            lockReservedQuantity(items, Long.valueOf(procuredOrderId));
        }

        //插入新的退货明细
        paymentReturnService.saveBatch(items);

        //审核表插入审核流程记录
        paymentRequestProcessService.insertPaymentRequestProcessQuash(pr.getPaymentRequestId(), templateDetails, userId);

        //采购订单退款状态（0未申请退款，1部分申请退款，2已全部申请退款，3部分退款，4已全部退款）
        getProcuredOrderReturnStatus(Long.valueOf(procuredOrderId));

        //申请方式（0预付款，1应付款，2仅退款，3退货退款，4换货）
        if(!paymentType.equals("0") && !paymentType.equals("1")){
            //更新采购订单状态：订单状态：0正常，1已完结，2仅退款中，3退货退款中，4换货中，5仅退款已驳回，6退货退款已驳回，7换货已驳回，8未完结
            setProcuredOrderStatus(Long.valueOf(procuredOrderId));
        }

        return rows;
    }

    /**
     * 更新采购订单状态
     * @return
     */
    public void setProcuredOrderStatus(Long procuredOrderId) {
        //更新采购订单状态：0正常，1已完结，2未完结，3仅退款中，4退货退款中，5换货中，6仅退款已驳回，7退货退款已驳回，8换货已驳回
        Integer status = procuredOrdersMapper.getProcuredOrderStatus(procuredOrderId);
        ProcuredOrders p = new ProcuredOrders();
        p.setOrdersId(procuredOrderId);
        p.setStatus(String.valueOf(status));
        procuredOrdersMapper.updateProcuredOrders(p);
    }

    @Override
    public ProcuredOrders selectById(String procuredOrderId) {
        return procuredOrdersMapper.selectByOrderId(Long.valueOf(procuredOrderId));
    }

    @Override
    public List<Long> selectList(Long planId) {
        return procuredOrdersMapper.selectPlanOrderNumber(planId);
    }

    @Override
    public int updateStatus(String procuredOrderId) {
        return procuredOrdersMapper.updateStatus(procuredOrderId,"9");
    }

    @Override
    public int updateCancelStyleClass(String procuredOrderId) {
        return procuredOrdersMapper.updateCancelStyleClassByOrdersId(Integer.valueOf(procuredOrderId));
    }

    /**
     * 采购订单付款状态
     * @param procuredOrderId
     * @return
     */
    public void getProcuredOrderPaymentStatus(Long procuredOrderId) {

        ProcuredOrders procuredOrder = procuredOrdersMapper.selectProcuredOrdersByOrdersId(procuredOrderId);
        BigDecimal orderAmount = procuredOrder.getAmountDue();
        String paymentStatus = "1";//（0未申请付款，1部分申请付款，2已全部申请付款，3部分付款，4已全部付款）
        //查询申请款总金额
        BigDecimal totalRequestedAmount = paymentRequestMapper.sumAmountByProcuredOrderId(procuredOrderId);

        //全部申请付款
        if (orderAmount != null && totalRequestedAmount != null && orderAmount.compareTo(totalRequestedAmount) == 0 && !procuredOrder.getPaymentStatus().equals("3")) {
            paymentStatus = "2";
        }

        ProcuredOrders p = new ProcuredOrders();
        p.setOrdersId(procuredOrder.getOrdersId());
        p.setPaymentStatus(paymentStatus);
        procuredOrdersMapper.updateProcuredOrders(p);

    }
    /**
     * 采购订单退款状态
     * @param procuredOrderId
     * @return
     */
    public void getProcuredOrderReturnStatus(Long procuredOrderId) {

        ProcuredOrders procuredOrder = procuredOrdersMapper.selectProcuredOrdersByOrdersId(procuredOrderId);
        String returnStatus = "1";//采购订单退款状态（0未申请退款，1部分申请退款，2已全部申请退款，3部分退款，4已全部退款）
        //查询申请款总金额
        BigDecimal totalRequestedAmount = paymentRequestMapper.sumAmountByProcuredOrderId(procuredOrderId);

        //查询申请款总退款金额
        BigDecimal totalReturnAmount = paymentRequestMapper.sumReturnAmountByProcuredOrderId(procuredOrderId);

        //全部申请付款
        if (totalRequestedAmount != null && totalReturnAmount != null && totalRequestedAmount.compareTo(totalReturnAmount) == 0 && !procuredOrder.getPaymentStatus().equals("3")) {
            returnStatus = "2";
        }

        ProcuredOrders p = new ProcuredOrders();
        p.setOrdersId(procuredOrder.getOrdersId());
        p.setReturnStatus(returnStatus);
        procuredOrdersMapper.updateProcuredOrders(p);

    }
    /**
     * 查询该采购下所申请的记录数据
     * @param paymentRequest
     * @return
     */
    @Override
    public List<PaymentRequest> selectPaymentRequestList(PaymentRequest paymentRequest) {
        return paymentRequestMapper.selectPaymentRequestList(paymentRequest);
    }

    /**
     * 取消申请
     * @param paymentRequestIds
     * @return
     */
    @Override
    public int setCancelPaymentRequestByIds(List<String> paymentRequestIds, String nickname) {
        LambdaUpdateWrapper<PaymentRequest> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(PaymentRequest::getPaymentRequestId, paymentRequestIds);
        updateWrapper.set(PaymentRequest::getUpdateBy, nickname);
        updateWrapper.set(PaymentRequest::getUpdateTime, DateUtils.getNowDate());
        updateWrapper.set(PaymentRequest::getCancelStatus, Constants.CANCEL_STATUS_ONE);
        int pr = paymentRequestMapper.update(null, updateWrapper);
        return pr;
    }

    /**
     * 审核记录
     * @param reviewStatus,deptId,userId,applicant
     * @return
     */
    @Override
    public List<PaymentRequest> selectPaymentRequestByStatus(Long reviewStatus, Long deptId, Long userId, String applicant) {

        List<PaymentRequest> paymentRequestList = new ArrayList<>();

        Long pending = Long.valueOf(Constants.PAYMENT_REVIEW_STATUS_PENDING);//审核中
        Long approved = Long.valueOf(Constants.PAYMENT_REVIEW_STATUS_APPROVED);//已审核

        if(reviewStatus.equals(pending)){
            //待我审核
            Long reviewerUserId = userId;//sysUserRoleMapper.selectById(userId).getRoleId();
            paymentRequestList = paymentRequestMapper.selectPaymentRequestByStatus(reviewStatus,reviewerUserId,null,applicant,false,null);
        }else if(reviewStatus.equals(approved)){
            //我已审核
            paymentRequestList = paymentRequestMapper.selectPaymentRequestByStatus(null,null,null,applicant,true,userId);
        }else{
            //我的发起
            paymentRequestList = paymentRequestMapper.selectPaymentRequestByStatus(null,null,userId,applicant,false,null);
        }

        return paymentRequestList ;
    }

    //校验用户和角色之前的联动关系
    private String checkSysUserRole(Long userId){

        //根据用户ID查询对应的角色，层级往上查询
        SysUserRole nowSur = sysUserRoleMapper.selectById(userId);
        if(nowSur == null){
            throw new ServiceException("当前用户未分配角色，请联系管理员分配角色后再操作。");
        }

        Long roleId = nowSur.getRoleId();
        SysRole sysRole = sysRoleMapper.selectRoleById(roleId);
        String ancestors = sysRole.getAncestors();//roleIds
        String[] ancestorArray = ancestors.split(",");
        //根据祖级列表角色ID查询对应的用户
        for (String ancestor : ancestorArray) {
            if (!ancestor.equals("0")) { // 排除掉0
                LambdaQueryWrapper<SysUserRole> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(SysUserRole::getRoleId, ancestor);
                SysUserRole parentSur = sysUserRoleMapper.selectOne(queryWrapper);
                SysRole sr = sysRoleMapper.selectRoleById(Long.valueOf(ancestor));
                if(parentSur == null){
                    throw new ServiceException("角色【"+sr.getRoleName()+"】未分配用户，请联系管理员分配用户后再操作。");
                }
            }
        }

        return ancestors;
    }

    /**
     * 生成随机数
     * @return
     */
    private String generateRequestCode(int size) {
        // 获取当前日期
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
        String currentDate = dateFormat.format(new Date());

        // 获取序列号
        String paymentVoucherOrder = paymentRequestMapper.selectPaymentRequestCode();
        String randomNumber;
        // ...根据自己的业务逻辑实现获取序列号的方法
        if(StringUtils.isEmpty(paymentVoucherOrder)){
            randomNumber = Constants.RANDOM_NUMBERS;
        }else{
            randomNumber = String.format("%04d", (NumberUtils.parseNumber(paymentVoucherOrder.substring(10),Long.class)+(size+1)));
        }

        // 拼接生成的代码
        String code = Constants.CODE_REQUSET + currentDate + randomNumber;

        return code;
    }

    /**
     * 检查模板
     * @return
     */
    private List<TemplateDetail> CheckTemplateDetail(Long userId, String componentPath){
        //获取菜单ID
        SysMenu sysMenu = sysMenuMapper.selectMenuByComponent(componentPath);
        if(sysMenu == null){
            throw new ServiceException("获取菜单ID失败，请刷新页面重新操作");
        }

        //校验当前菜单和用户是否绑定
        String templateId= templateMapper.findTemplateIdByUserIdAndMenuId(userId, sysMenu.getMenuId());
        if(StringUtils.isNull(templateId)||templateId == null){
            throw new ServiceException("未匹配到对应的审核模板，请联系人事匹配后再操作");
        }

        //获取模板详情
        List<TemplateDetail> templateDetails = templateDetailService.getTemplateDetailList(templateId);
        if(templateDetails.isEmpty()||templateDetails == null){
            throw new ServiceException("获取模板详情失败");
        }
        return templateDetails;
    }
    /**
     * 申请退款，更新商品库存锁定
     * @return
     */
    @Transactional
    public void lockReservedQuantity(List<PaymentReturn> items, Long procuredOrderId){
       ProcuredStorageDto dto  = procuredStorageApi.selectWarehouseIdByOrdersId(procuredOrderId);
       if(dto == null){
           throw new ServiceException("获取采购入库单对象失败");
       }
        items.stream().forEach(item -> {
            String sku = item.getSku();
            Integer available = item.getQuantity();
            LocalInventoryDto lto = localInventoryApi.selectLocalInventoryBySkuAndWarehouseId(sku, dto.getWarehouseId());
            if(lto == null){
                throw new ServiceException("获取"+sku+"库存信息失败");
            }
            BigDecimal oldReservedQuantity = lto.getReservedQuantity();
            if (oldReservedQuantity == null) {
                oldReservedQuantity = BigDecimal.ZERO;
            }
            lto.setReservedQuantity(oldReservedQuantity.add(BigDecimal.valueOf(available)));
            localInventoryApi.updateReservedQuantity(lto);
        });
    }
}
